package version1;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.Random;
import java.util.Set;

import version2.RWComparator;

public class RandomWalk {

	private HashMap<Integer, HashMap<Integer, Integer>> npList;
	private HashMap<Integer, HashMap<Integer, Integer>> contextList;
	private HashMap<Integer, ArrayList<Integer>> probability;
	private HashMap<Integer, Integer> reachedNum;
	// private HashMap<Integer, Double> prob;
	private double[] prob;
	private ArrayList<Double> sum;
	public static int numtimes = 10000;

	public RandomWalk() {
		npList = new HashMap<Integer, HashMap<Integer, Integer>>();
		// prob = new HashMap<Integer, Double>();
		contextList = new HashMap<Integer, HashMap<Integer, Integer>>();
		probability = new HashMap<Integer, ArrayList<Integer>>();
		reachedNum = new HashMap<Integer, Integer>();
		prob = new double[99401];
		sum = new ArrayList<Double>();

	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		RandomWalk rw = new RandomWalk();
		rw.readNP("matrix1.txt");
		System.out.println("read matrix1 ok");
		rw.readContext("matrix2.txt");
		System.out.println("read matrix2 ok");
		// rw.readProbability("context.txt");
		rw.assignProbability();
		// rw.sumProbability();
		// int numtimes = 10000;
		rw.walk(6, numtimes);

	}

	public void assignProbability() {
		for (int i = 1; i < 99401; i++) {
			prob[i] = 1.0 / 99400.0;
		}

	}

	public void walk(int noun, int numtimes) {
		for (int i = 0; i < numtimes; i++) {
			// System.out.println(i);
			if (i == 100) {
				// System.out.println("====================================100================================");
				// outputNP();
				Set<Integer> keys = reachedNum.keySet();
				for (int a : keys) {
					System.out.println(i + "\t" + a + "\t" + reachedNum.get(a));
				}

			} else if (i == 1000) {
				// System.out.println("====================================1000================================");
				// outputNP();
				Set<Integer> keys = reachedNum.keySet();
				for (int a : keys) {
					System.out.println(i + "\t" + a + "\t" + reachedNum.get(a));
				}

			} else if (i == 9999) {
				// System.out.println("====================================9999================================");
				// outputNP();
				Set<Integer> keys = reachedNum.keySet();
				for (int a : keys) {
					System.out.println(i + "\t" + a + "\t" + reachedNum.get(a));
				}

			}
			int context = chooseContext(noun);
			int np = chooseNP(context);
			saveNPNumber(np);

		}
		updateWeights();
	}

	public void outputNP() {
		Set<Integer> keys = reachedNum.keySet();
		ArrayList<Integer> keyarray = new ArrayList<Integer>(keys);

		Collections.sort(keyarray, new RWComparator(reachedNum));
		for (int i = 0; i < 1000; i++) {
			System.out.println(keyarray.get(i) + ": "
					+ reachedNum.get(keyarray.get(i)));
		}
	}

	public void updateWeights() {

		// set all the context's prob to 0;
		// for (Iterator<Entry<Integer, Double>> it =
		// prob.entrySet().iterator(); it.hasNext();) {
		// Entry<Integer, Double> e = it.next();
		// // int c1 = (Integer) e.getKey();
		// e.setValue(0.);
		// }


		for(int i = 1; i< 99401; i++){
			prob[i] =0;
		}
		// update
		int sumall = 0;
		for (Iterator<Entry<Integer, Integer>> iter = reachedNum.entrySet()
				.iterator(); iter.hasNext();) {

			Entry<Integer, Integer> entry = iter.next();
			int np = entry.getKey();
			int reachedTimes = entry.getValue();
			HashMap<Integer, Integer> contexts = contextList.get(np);

			Set<Integer> contextSet = contexts.keySet();
			for (int c : contextSet) {
				prob[c] += reachedTimes;
				sumall += reachedTimes;
			}
			
			

			// for (Iterator<Entry<Integer, Double>> it =
			// prob.entrySet().iterator(); it.hasNext();) {
			//
			// Entry<Integer, Double> e = it.next();
			// //int c = e.getKey();
			// double number = e.getValue();
			//
			// double newNumber = number + reachedTimes;
			// e.setValue(newNumber);
			// }

		}
	
		for(int i = 0; i<99401; i++){
			prob[i] = prob[i] / sumall;
		}
		
		
	}

	public void saveNPNumber(int np) {
		if (reachedNum.containsKey(np)) {
			reachedNum.put(np, reachedNum.get(np) + 1);

		} else {
			reachedNum.put(np, 1);
		}
		// System.out.println(reachedNum);
	}

	public int chooseNP(int context) {
		HashMap<Integer, Integer> nps = npList.get(context);

		Set<Integer> npss = nps.keySet();
		ArrayList<Integer> nparray = new ArrayList<Integer>(npss);
		Random r = new Random();
		int rn = r.nextInt(nparray.size());

		return nparray.get(rn);

	}

	public int chooseContext(int np) {
		// ArrayList<Integer> randomProb = probability.get(np);
		// int size = randomProb.size();
		// Random r = new Random();
		// int randomNum = r.nextInt(size);
		// return randomProb.get(randomNum);

		HashMap<Integer, Integer> contextlist = contextList.get(np);
		Set<Integer> cs = contextlist.keySet();
		sum.clear();
		HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
		double temp = 0;
		int j = 0;
		for (int c : cs) {
			map.put(j, c);
			j++;
			temp += prob[c];
			sum.add(temp);
		}

		Random r = new Random();
		double rd = r.nextDouble() * temp;

		int targetContext = 0;
		for (int i = 0; i < sum.size(); i++) {
			if (sum.get(i) >= rd)
				targetContext = i;
			break;
		}

		return map.get(targetContext);

	}

//	public void readProbability(String filename) {
//
//		try {
//			// HashMap<Integer, Double> prob = new HashMap<Integer, Double>();
//			BufferedReader br = new BufferedReader(new FileReader(filename));
//			String line;
//
//			while ((line = br.readLine()) != null) {
//				String[] str = line.split("\\s+");
//				int context = Integer.parseInt(str[0]);
//				double p = Double.parseDouble(str[1]);
//
//				//
//				// for(int i = 0; i < p * 100; i++){
//				// probability.add(context);
//				// }
//
//				prob.put(context, p);
//
//			}
//
//			// Set<Entry<Integer, HashMap<Integer, Integer>>> entries =
//			// contextList.entrySet();
//
//			for (Iterator<Entry<Integer, HashMap<Integer, Integer>>> iter = contextList
//					.entrySet().iterator(); iter.hasNext();) {
//
//				Entry<Integer, HashMap<Integer, Integer>> entry = iter.next();
//				int np = entry.getKey();
//				HashMap<Integer, Integer> contexts = entry.getValue();
//				ArrayList<Integer> randomProb = new ArrayList<Integer>();
//
//				for (Iterator<Entry<Integer, Integer>> it = contexts.entrySet()
//						.iterator(); it.hasNext();) {
//					Entry<Integer, Integer> e = it.next();
//					int c = e.getKey();
//					Double p = prob.get(c);
//
//					for (int i = 0; i < p * 100; i++) {
//						randomProb.add(c);
//					}
//
//				}
//				probability.put(np, randomProb);
//			}
//
//		} catch (FileNotFoundException e) {
//			// TODO Auto-generated catch block
//			e.printStackTrace();
//		} catch (IOException e) {
//			// TODO Auto-generated catch block
//			e.printStackTrace();
//		}
//		// System.out.println(probability);
//	}

	public void readContext(String filename) {

		try {
			BufferedReader br = new BufferedReader(new FileReader(filename));

			int npNum = 0;
			HashMap<Integer, Integer> context = null;
			String line;

			while ((line = br.readLine()) != null) {
				String[] str = line.split("\\s+");
				int npNumber = Integer.parseInt(str[0]);

				if (npNumber != npNum) {
					contextList.put(npNum, context);
					context = new HashMap<Integer, Integer>();
					npNum = npNumber;
				}

				context.put(Integer.parseInt(str[1]), Integer.parseInt(str[2]));

			}
			br.close();
			contextList.remove(0);
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NumberFormatException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		// System.out.println(contextList);

	}

	public void readNP(String filename) {

		try {
			BufferedReader br = new BufferedReader(new FileReader(filename));
			String line;
			int contextNum = 0;
			HashMap<Integer, Integer> np = null;
			while ((line = br.readLine()) != null) {

				String[] str = line.split("\\s+");

				// System.out.println(str[0]);
				int c = Integer.parseInt(str[1]);
				// System.out.println(c);
				if (c != contextNum) {
					npList.put(contextNum, np);
					np = new HashMap<Integer, Integer>();
					contextNum = c;
				}

				np.put(Integer.parseInt(str[0]), Integer.parseInt(str[2]));

			}
			br.close();
			npList.remove(0);

		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		// System.out.println(npList);
	}

}
